const colors = [
  "red",
  "green",
  "blue",
  "gray",
  "pink",
  "purple",
  "yellow",
  "orange"
];
function getRandomColor(arr, num = 5) {
  let arrLength = arr.length;
  let tmp = [];
  for (let i = 0; i < num; i++) {
    tmp.push(arr[Math.floor(Math.random() * arrLength)]);
  }
  return tmp;
}

function h (nodeName, attrs, ...children) {
  return { nodeName, attrs, children };
}
const renderNode = vnode => {
  let el;
  if (typeof vnode === 'string') {
    return document.createTextNode(vnode);
  }
  const { nodeName, attributes, children } = vnode;

  if (typeof nodeName === "string") {
    el = document.createElement(nodeName);
    for (let key in attributes) {
      el.setAttribute(key, attrs[key]);
    }
  } else if (typeof nodeName === "function") {
    const component = new nodeName(attributes);
    el = renderNode(component.render(component.props, component.state));
    component.base = el;
  }

  (children || []).forEach(child => el.appendChild(renderNode(child)))

  return el;
};
class Component {
  constructor(props) {
    this.props = props;
    this.state = {};
  }
  setState(state) {
    this.state = Object.assign({}, state);
    renderComponent(this);
  }
}
const renderComponent = (component, parent) => {
  // const oldBase = component.base;
  // component.base = renderNode(
  //   component.render(component.props, component.state)
  // );
  // if (parent) {
  //   parent.appendChild(component.base);
  // } else {
  //   oldBase.parentNode.replaceChild(component.base, oldBase);
  // }
  let rendered = component.render(component.props, component.state);
  component.base = diff(component.base, rendered)
};
class Person extends Component {
  constructor(props) {
    super(props);

    this.state = {
      list: getRandomColor(colors)
    };
    this.timer = setInterval(_ => {
        this.setState({
            list: getRandomColor(colors)
          });        
    }, 1000)

  }
  render(props, state) {
    return h("ul", null, ...state.list.map(item => h("li", null, item)));
  }
}
class App extends Component {
  render() {
    return h(
      "div",
      { class: "app" },
      h("h1", null, "Simple vDOM"),
      h(Person)
    );
  }
}
const diff = (dom, vnode, parent) => {
  if (dom) {
    if (typeof vnode === "string") {
      dom.nodeValue = vnode;

      return dom;
    }
    if (typeof vnode.nodeName === "function") {
      const component = new vnode.nodeName(vnode.attributes);
      const rendered = component.render(component.props, component.state);

      diff(dom, rendered);
      return dom;
    }

    // Naive check for number of chilren of vNode and dom
    if (vnode.children.length !== dom.childNodes.length) {
      dom.appendChild(
        // render only the last child
        renderNode(vnode.children[vnode.children.length - 1])
      );
    }

    // run diffing for children
    dom.childNodes.forEach((child, i) => diff(child, vnode.children[i]));

    return dom;
  } else {
    const newDom = renderNode(vnode);
    parent.appendChild(newDom);
    return newDom;
  }
};

const render = (vnode, parent) => {
  diff(undefined, vnode, parent);
};
render(h(App), document.body);
